package impl

import (
	"fmt"
	"github.com/starmotioncf/common/payment"
	"github.com/starmotioncf/common/payment/dukpay"
	"github.com/starmotioncf/common/payment/ogood"
	"github.com/starmotioncf/common/payment/payermax"
	"github.com/starmotioncf/common/payment/paypal"
	"github.com/starmotioncf/common/payment/v5pay"
	"github.com/starmotioncf/soutchatinternal/dto"
	"github.com/starmotioncf/soutchatinternal/repository"
	"github.com/starmotioncf/soutchatinternal/service"
	errs2 "github.com/zeebo/errs"
	"log"
	"net/url"

	"github.com/gin-gonic/gin"
)

type paymentService struct {
	*service.Service
	ReturnPage       string
	channelProviders map[payment.Channel]payment.ChannelProvider
	orderRepo        repository.OrderRepository
}

func NewPaymentService(s *service.Service, conf service.PaymentConfig, orderRepo repository.OrderRepository) (service.PaymentService, error) {
	_s := &paymentService{
		Service:          s,
		ReturnPage:       conf.ReturnPage,
		orderRepo:        orderRepo,
		channelProviders: map[payment.Channel]payment.ChannelProvider{},
	}
	err := _s.initChannelProvider(conf)
	return _s, err
}

// GetPaymentMethods 获取支付方式，方式包含产品列表，要根据是否代理判断
//func (s *paymentService) GetPaymentMethods(ctx *gin.Context, isAgent bool, req *dto.PaymentMethodReq) (res []*dto.PaymentMethodItem, err error) {
//	return nil, nil
//}

// CreateOrder 创建订单，要根据是否代理判断
func (s *paymentService) CreateOrder(ctx *gin.Context, isAgent bool, req *dto.PaymentCreateOrderReq) (res *dto.PaymentCreateOrderRes, err error) {
	//order := &model.Order{} //
	return nil, nil
}

// QueryOrder 查询订单支付状态
func (s *paymentService) QueryOrder(ctx *gin.Context, req *dto.PaymentQueryOrderReq) (res *dto.PaymentQueryOrderRes, err error) {
	return nil, nil
}

// Return PayPal支付回调地址，在重定向到前段页面
func (s *paymentService) Return(ctx *gin.Context) string {
	// todo 从配置中获取,跳转到前端的支付结果页
	rUrl, err := url.Parse(s.ReturnPage)
	if err != nil || rUrl == nil {
		log.Println("payment支付返回地址配置错误，请检查！")
		return "/"
	}
	channel := payment.Channel(ctx.Param("channel"))
	channelProvider, err := s.getChannelProvider(channel)
	if err != nil {
		log.Println(err)
		return "/"
	}
	returnResp, err := channelProvider.Return(ctx, ctx.Request)
	if err != nil {
		log.Println(err)
		return "/"
	}
	//order, err := s.orderRepo.GetByOrderNo(ctx, returnResp.GetOrderNo())
	//if err != nil {
	//	logs.Error("[V5payReturn] 获取订单出错:", err.Error())
	//	return ""
	//}

	// 更新外部订单号
	// if order != nil && order.TransactionId == "" {
	// 	order.TransactionId = req.TransactionId
	// 	err = s.orderRepo.Update(ctx, order, "transactionid")
	// 	if err != nil {
	// 		logs.Error("[V5payReturn] 更新外部订单号出错:", err.Error())
	// 	}
	// }

	query := rUrl.Query()
	for k, v := range map[string]string{
		"tradeNo": returnResp.GetTradeNo(),
		"orderNo": returnResp.GetOrderNo(),
	} {
		query.Set(k, v)
	}
	rUrl.RawQuery = query.Encode()
	return rUrl.String()
}

// Notify 回调通知
func (s *paymentService) Notify(ctx *gin.Context) error {
	channel := payment.Channel(ctx.Param("channel"))
	channelProvider, err := s.getChannelProvider(channel)
	if err != nil {
		return err
	}
	notifyResp, err := channelProvider.Notify(ctx, ctx.Request)
	if err != nil {
		return err
	}
	//order, err := s.orderRepo.GetByOrderNo(ctx, notifyResp.GetOrderNo())
	//if err != nil {
	//	return err
	//}
	fmt.Println(notifyResp)
	return nil
}

// 初始化支付服务商
func (s *paymentService) initChannelProvider(conf service.PaymentConfig) error {
	var cp payment.ChannelProvider
	errs := errs2.Group{}
	var err error
	cp, err = payermax.NewPayermax(conf.Payermax)
	if err != nil {
		errs.Add(err)
	} else {
		s.channelProviders[cp.Channel()] = cp
	}
	cp, err = paypal.NewPaypal(conf.Paypal)
	if err != nil {
		errs.Add(err)
	} else {
		s.channelProviders[cp.Channel()] = cp
	}

	cp, err = v5pay.NewV5pay(conf.V5pay)
	if err != nil {
		errs.Add(err)
	} else {
		s.channelProviders[cp.Channel()] = cp
	}

	cp, err = dukpay.NewDukpay(conf.Dukpay)
	if err != nil {
		errs.Add(err)
	} else {
		s.channelProviders[cp.Channel()] = cp
	}

	cp, err = ogood.NewOgood(conf.Ogood)
	if err != nil {
		errs.Add(err)
	} else {
		s.channelProviders[cp.Channel()] = cp
	}
	return errs.Err()
}

func (s *paymentService) getChannelProvider(channel payment.Channel) (cp payment.ChannelProvider, err error) {
	cp, ok := s.channelProviders[channel]
	if !ok {
		return nil, fmt.Errorf("payment channel[%s] not support", channel)
	}
	return cp, nil
}
